import { Matrix } from "../d2/math/Matrix";
import { Vec2 } from "../d2/math/Vec2";
import { IVec2 } from "../util/Defined";
import { ECSCmp } from "./ECSCmp";


const mat = new Matrix();
/**
 * [ECS]2d变换组件
 */
export default class CmpTrans extends ECSCmp {
	protected _rot: number;
	protected _dir = new Vec2();
	protected _dirChanged: boolean;
	protected _scale = new Vec2();
	protected _trans: Matrix;
	protected _transChanged: boolean;

	onAdd(): void {
		this._rot = 0;
		this._dirChanged = true;
		this._scale.setPos(1, 1);
		this._trans?.identity();
		this._transChanged = true;
	}

	/** 旋转值(弧度) */
	get rot() {
		return this._rot;
	}

	set rot(v: number) {
		this._rot = v;
		this._dirChanged = true;
		this._transChanged = true;
	}

	/** 朝向(请通过setDir或rot设置) */
	get dir(): Readonly<IVec2> {
		if (this._dirChanged) {
			this._dirChanged = false;
			this._dir.setPos(Math.cos(this._rot), Math.sin(this._rot));
		}
		return this._dir;
	}

	/** 缩放(请通过setScale设置) */
	get scale(): Readonly<IVec2> {
		return this._scale;
	}

	/**
	 * 设置朝向
	 * @param x
	 * @param y
	 */
	setDir(x: number, y: number) {
		Vec2.setPos(this.dir, x, y);
		this._rot = Math.atan2(y, x);
		this._transChanged = true;
	}

	/**
	 * 设置朝向
	 * @param dir
	 */
	setDirTo(dir: Readonly<IVec2>) {
		this.setDir(dir.x, dir.y);
	}

	/**
	 * 设置缩放
	 * @param x
	 * @param y
	 */
	setScale(x: number, y = x) {
		if (this.scale.x === x && this.scale.y === y) return;
		Vec2.setPos(this.scale, x, y);
		this._transChanged = true;
	}

	/**
	 * 朝向目标
	 * @param pos
	 */
	faceTo(pos: Readonly<IVec2>) {
		this.setDirTo(this.pos.dirTo(pos));
	}

	/** 旋转缩放变换矩阵 */
	get trans() {
		if (this._transChanged) {
			this._transChanged = false;
			const mat: Matrix = this._trans || (this._trans = new Matrix());
			if (this._rot || this.scale.x !== 1 || this.scale.y !== 1) {
				mat.setTranslate(0, 0).setScaleRotation(this._rot, this.scale.x, this.scale.y);
			} else {
				mat.identity();
			}
		}
		return this._trans;
	}

	/**
	 * 此组件坐标转化为场景坐标
	 * @param out 
	 */
	localToGlobal<T extends IVec2>(out: T) {
		return Vec2.addPosTo(this.trans.transformPoint(out), this.pos);
	}

	/**
	 * 场景坐标转化为此组件坐标
	 * @param out 
	 */
	globalToLocal<T extends IVec2>(out: T) {
		mat.a = this.trans.a;
		mat.b = this.trans.b;
		mat.c = this.trans.c;
		mat.d = this.trans.d;
		mat.tx = this.pos.x;
		mat.ty = this.pos.y;
		return mat.invertTransformPoint(out);
	}
}
